"""
数据库模块，包含MySQL、Redis
"""

import sys,os,redis
import traceback
from utils.log import Logger
from config.config import Config


_module_name_ = os.path.basename(__file__).split('.')[0]
_logger = Logger.get_logger(_module_name_)

class MysqlUtil:

    # module_name_ = os.path.basename(__file__).split('.')[0]
    # logger = Logger.get_logger(module_name_)
    _db_params = eval(Config().get('mysql_params'))
    def __init__(self, conninfo=_db_params):
        self.conninfo = conninfo
        # module_name_ = os.path.basename(__file__).split('.')[0]
        # self.logger = Logger.get_logger(module_name_)
        pass
    """
        获取数据库的连接
        参数依次是：IP地址,数据库登录名，数据库密码，数据库实体名称,指定字符集 （未指定可能出现中文乱码）
    """

    
    def get_conn(self):
        import pymysql
        conn = None
        try:
            # db_params = eval(Config().get('mysql_params'))
            conn = pymysql.connect(host=self.conninfo[0], user=self.conninfo[1],
                                   password=self.conninfo[2], database=self.conninfo[3], charset=self.conninfo[4])
        except Exception as e:
            _logger.error('数据库连接失败' + str(e))
        return conn

    
    def db_query(self, sql):
        """
        数据库查询
        :param sql: 查询sql语句
        :return: 返回查询的所有结果，结果集为对象，如果没有，返回None
        """
        conn = self.get_conn()
        if conn != None:
            result = None
            cursor = conn.cursor()  # 创建游标
            try:
                cursor.execute(sql)
                result = cursor.fetchall()
            except Exception as e:
                _logger.error('sql错误' + str(e))
            finally:
                cursor.close()
                conn.close()
            return result
        else:
            return None

    
    def db_update(self, sql):
        """
        更新数据
        :param sql: 更新数据库的sql语句
        :return: 更新成功返回Ture，失败返回False
        """
        conn = self.get_conn()
        flag = False  # 用于判断增删改是否执行成功的标记
        if conn != None:
            cursor = conn.cursor()
            try:
                cursor.execute(sql)
                conn.commit()  # 增删改后提交至数据库
                flag = True
            except Exception as e:
                _logger.error('sql错误' + str(e))
            finally:
                cursor.close()
                conn.close()
        return flag

    '''
          创建数据表
          tableName：数据表名称
          sql： 数据表的创建sql语句
    '''
    
    def createTable(self, tableName, sql):
        """
        创建表
        :param tableName: 数据库表名
        :param sql: 创建数据库表的sql语句
        :return:
        """
        # 获取数据库连接
        conn = self.get_conn()
        # 使用cursor() 方法创建一个游标对象 cursor
        cursor = conn.cursor()
        # 使用execute()方法执行sql ，如果表存在则删除
        cursor.execute("drop table if exists %s" % (tableName))
        # 使用预处理语句创建表
        cursor.execute(sql)
        # 关闭数据库连接
        conn.close()

    
    def insertTable(self, sql):
        """
        插入数据
        :param sql: 插入数据的sql语句
        :return:
        """
        # 获取数据库连接
        conn = self.get_conn()
        # 使用cursor() 方法创建一个游标对象 cursor
        cursor = conn.cursor()

        try:
            # 执行sql语句
            cursor.execute(sql)
            # 提交到数据库执行
            conn.commit()
        except Exception as e:  # 方法一：捕获所有异常
            # 如果发生异常，则回滚
            # print("发生异常", Exception)
            _logger.error('sql错误' + str(e))
            conn.rollback()
        finally:
            # 最终关闭数据库连接
            conn.close()

    
    def fetchone(self, sql):
        """
        查询数据库，单个结果集
        :param sql: 查询sql语句
        :return: 该方法获取下一个查询结果集。结果集是一个对象
        """
        # 获取数据库连接
        conn = self.get_conn()
        # 使用cursor() 方法创建一个游标对象 cursor
        cursor = conn.cursor()
        result = False
        try:
            # 执行sql语句
            cursor.execute(sql)
            result = cursor.fetchone()
        except:  # 方法二：采用traceback模块查看异常
            # 输出异常信息
            traceback.print_exc()
            # 如果发生异常，则回滚
            conn.rollback()
        finally:
            # 最终关闭数据库连接
            conn.close()
        return result

    '''
        查询数据库：多个结果集
        fetchall(): 接收全部的返回结果行.
    '''

    
    def fetchall(self, sql):
        """
        查询数据库：多个结果集
        :param sql:
        :return: 接收全部的返回结果行
        """
        # 获取数据库连接
        conn = self.get_conn()
        # 使用cursor() 方法创建一个游标对象 cursor
        cursor = conn.cursor()
        results = False
        try:
            # 执行sql语句
            cursor.execute(sql)
            results = cursor.fetchall()
        except:  # 方法三：采用sys模块回溯最后的异常
            # 输出异常信息
            info = sys.exc_info()
            print(info[0], ":", info[1])
            # 如果发生异常，则回滚
            conn.rollback()
        finally:
            # 最终关闭数据库连接
            conn.close()
        return results

    def delete(self, sql):
        """
        删除结果集
        :param sql: 删除sql语句
        :return:
        """
        # 获取数据库连接
        conn = self.get_conn()
        # 使用cursor() 方法创建一个游标对象 cursor
        cursor = conn.cursor()
        try:
            # 执行sql语句
            cursor.execute(sql)
            conn.commit()
        except:  # 如果你还想把这些异常保存到一个日志文件中，来分析这些异常
            # 将错误日志输入到目录文件中
            f = open("c:log.txt", 'a')
            traceback.print_exc(file=f)
            f.flush()
            f.close()
            # 如果发生异常，则回滚
            conn.rollback()
        finally:
            # 最终关闭数据库连接
            conn.close()

    
    def update(self, sql):
        """
        更新结果集
        :param sql:
        :return:
        """
        # 获取数据库连接
        conn = self.get_conn()
        # 使用cursor() 方法创建一个游标对象 cursor
        cursor = conn.cursor()
        flag = False
        try:
            # 执行sql语句
            cursor.execute(sql)
            conn.commit()
            flag = True
        except Exception as e:
            # 如果发生异常，则回滚
            _logger.error('sql错误' + str(e))
            conn.rollback()
        finally:
            # 最终关闭数据库连接
            conn.close()
        return flag

class RedisUtil:
# 登录：从mysql数据库中获取user表账号密码，缓存至redis中；生成4位英文和数字的验证码缓存至redis中；完成登录操作
    module_name_ = os.path.basename(__file__).split('.')[0]
    logger = Logger.get_logger(module_name_)
    redis_params = Config().get('redis_params')
    random_code = Config().get('random_code')

    
    def incrypt_md5(self, str):
        # md5加密
        import hashlib
        md5 = hashlib.md5()
        md5.update(str.encode())
        return md5.hexdigest()

    
    def get_red_conn(self):
        """
        返回redis连接器对象
        :return:
        """
        conn = None
        try:
            pool = redis.ConnectionPool(**self.redis_params)
            conn = redis.Redis(connection_pool=pool)
        except Exception as e:
            _logger.error('路径错误' + str(e))
        return conn

    
    def get_verifycode(self):
        """
        返回4位数字字母混合的字符串
        :return:
        """
        import random
        code = ''
        for i in range(0,4):
            index = random.randint(0,len(self.random_code)-1)
            code += self.random_code[index]
        return code
"""
    
    def update_db(self, sql):
        conn = self.get_db_conn()
        cur = conn.cursor()
        cur.execute(sql)
        conn.commit()
        cur.close()
        conn.close()

    
    def query_all(self, sql):
        conn = self.get_db_conn()
        cur = conn.cursor()
        cur.execute(sql)
        result = cur.fetchall()
        cur.close()
        conn.close()
        return result
class Login:
    def add_user(self):
        while 1:
            uname = input('账号：')
            upass = input('密码：')
            passwd = RedisUtil.incrypt_md5(upass)
            realname = input('真实姓名：')
            uphone = input('电话：')
            sql = f'insert into `user`(username,`password`,realname,phone) ' \
                  f'values("{uname}","{passwd}","{realname}","{uphone}")'
            RedisUtil.update_db(sql)
            choice = input('需要继续添加吗(y/n)?')
            if choice != "y":
                break
    def get_login_info(self):
        sql = 'select username,`password` from user'
        result = RedisUtil.query_all(sql)
        red = RedisUtil.get_red_conn()
        for r in result:
            red.hset('acc_info', r[0], r[1])
        return red.hgetall('acc_info')
    def login(self):
        acc_name = input("输入账号：")
        acc_pass = input("输入密码：")
        spass = RedisUtil.incrypt_md5(acc_pass)
        red = RedisUtil.get_red_conn()
        # 生成验证码，用户输入验证码，比对之后的三个结果，包括相同则退出循环，不相同重新输入，验证码过期也要重新输入
        while 1:
            verifycode = RedisUtil.get_verifycode()
            red.set("vfcode", verifycode)
            red.expire("vfcode", 10)
            print("验证码:" + verifycode)
            uer_vfcode = input("请输入验证码")
            try:
                if red.get("vfcode")+"" == uer_vfcode.upper():
                    break
                else:
                    print('验证码输入错误')
            except Exception as e:
                print('验证码过期')
        acc_info = self.get_login_info()
        if acc_info[acc_name] != spass:
            print("账号或密码错误")
        else:
            print("登录成功")
"""

if __name__ == '__main__':
    # with open('../config/src/mysql.json', encoding='utf-8') as f:
    #     info = json.load(f)
    # DBUtil().getConnect(**info)
    # print(info)
    # print(MysqlUtil.get_conn())
    r = RedisUtil.random_code
    print(r,type(r))
    pass